package simple.cat.server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import simple.cat.servlet.HttpServlet;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author zheng9feng
 * @Description 容器启动类
 * @Date 2020/12/24 21:43
 */
public class BootStrap {
	
	/**
	 * 默认监听端口号
	 */
	private int port = 8080;
	
	/**
	 * url与servlet映射
	 */
	private HashMap<String, HttpServlet> servletMap = new HashMap<>();
	
	
	public int getPort() {
		return port;
	}
	
	public void setPort(int port) {
		this.port = port;
	}
	
	public HashMap<String, HttpServlet> getServletMap() {
		return servletMap;
	}
	
	public void setServletMap(HashMap<String, HttpServlet> servletMap) {
		this.servletMap = servletMap;
	}
	
	/**
	 * 容器启动后初始化操作
	 */
	public void start() throws Exception {
		// 解析server.xml 封装
		loadServer();
		
		// 加载servlet
		loadServlet();
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 50, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("服务器启动,监听端口------------>" + port);
		while (true) {
			Socket socket = serverSocket.accept();
			RequestProcessor requestProcessor = new RequestProcessor(socket, servletMap);
			threadPoolExecutor.execute(requestProcessor);
			// requestProcessor.start();
			// // 打印请求
			// InputStream inputStream = socket.getInputStream();
			// // 防止网络延迟导致的输入流无数据
			// // 只有在获取到的输入流里有可用数据时才往后执行
			// // int available = 0;
			// // while (available == 0) {
			// // 	available = inputStream.available();
			// // }
			//
			// // byte[] data = new byte[available];
			// // inputStream.read(data);
			// // System.out.println("请求:");
			// // System.out.println(new String(data));
			//
			// //
			// // get请求基本格式
			// // GET /halo HTTP/1.1
			// // Host: localhost:8080
			// // Connection: keep-alive
			// // Pragma: no-cache
			// // Cache-Control: no-cache
			// // Upgrade-Insecure-Requests: 1
			// // User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
			// // 空行
			//
			// Request request = new Request(inputStream);
			//
			// OutputStream outputStream = socket.getOutputStream();
			// Response response = new Response(outputStream);
			// String url = request.getUrl();
			// response.buildResourceAbsolutePath(url);
			//
			// // String responseString = "halo,simple tomcat!";
			// // // 根据输出字符串长度拼接输入内容
			// // responseString = HttpProtocolUtil.getHttpHeader4Success(responseString.getBytes().length) + responseString;
			// // response.output(responseString);
			//
			// // 根据url判断是静态资源请求还是动态资源请求
			// // 如果存在与url映射的servlet实例说明是动态请求,否则就是静态请求
			// HttpServlet httpServlet = servletMap.get(url);
			// if (httpServlet == null) {
			// 	// 输出静态资源文件
			// 	response.outputHtml();
			//
			// } else {
			// 	httpServlet.service(request, response);
			// }
			//
			// socket.close();
		}
	}
	
	/**
	 * 解析server.xml
	 */
	public void loadServer() {
		InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(inputStream);
			List<Element> serviceElements = document.selectNodes("//Service");
			for (Element serviceElement : serviceElements) {
				List<Element> connectorElments = serviceElement.selectNodes("//Connector");
				for (Element connectorElment : connectorElments) {
					String port = connectorElment.attributeValue("port");
					List<Element> hostElements = connectorElment.selectNodes("//Engine/Host");
					for (Element hostElement : hostElements) {
						String hostName = hostElement.attributeValue("name");
						String appBase = hostElement.attributeValue("appBase");
						appBase = appBase.replace("\\", "/");
						System.out.println("hostName=" + hostName + ",appBase=" + appBase);
						File file = new File(appBase);
						File[] files = file.listFiles();
						for (File dir : files) {
							if (dir.isDirectory()) {
								String appName = dir.getName();
								
								// 直接写固定路径
								String classPath = appBase + appName + "/";
								AppClassLoader appClassLoader = new AppClassLoader(classPath);
								Class<?> target = appClassLoader.findClass("simple.cat.servlet.DemoServlet");
								System.out.println(target.getClassLoader());
								HttpServlet httpServlet = (HttpServlet) target.newInstance();
							}
						}
					}
				}
			}
			
		} catch (DocumentException | ClassNotFoundException | IllegalAccessException | InstantiationException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 解析web.xml,存储url与servlet实例的映射关系
	 * 确定映射关系基本逻辑:
	 * servlet标签和servlet-mapping标签根据servlet-name进行关联
	 * 解析servlet标签根据servlet-name可以找到对应的servlet-mapping标签下的url-pattern标签
	 * key:url-pattern
	 * value:根据servlet-class实例化对象
	 */
	private void loadServlet() {
		InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
		SAXReader saxReader = new SAXReader();
		try {
			Document document = saxReader.read(inputStream);
			
			List<Element> servletElementList = document.selectNodes("//servlet");
			for (Element servletElement : servletElementList) {
				String servletName = servletElement.elementText("servlet-name");
				String servletClass = servletElement.elementText("servlet-class");
				
				// 根据servlet-name查找符合的servlet-mapping标签
				List<Element> servletMappingList = document.selectNodes("/web-app/servlet-mapping[servlet-name = '" + servletName + "']");
				for (Element servletMappingElement : servletMappingList) {
					String urlPattern = servletMappingElement.elementText("url-pattern");
					
					
					
					servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).getDeclaredConstructor().newInstance());
				}
			}
		} catch (DocumentException | ClassNotFoundException | NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		BootStrap bootStrap = new BootStrap();
		
		try {
			bootStrap.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
